# encoding: utf-8
"""
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    created by lane.chang on '17/10/2024'
    comment: 服务流程
"""
import json
from sqlalchemy import or_, func
from fastapi import APIRouter, Request, Body, Query, BackgroundTasks

from config import Config
from project.core.function import if_none, json_response
from project.lib.common import Global
from project.lib.decorator import api_common, exec_duration
from project.lib.constant import DEFAULT_VALUE
from project.model.basic import SopItem, InformConfig, InformType
from project.model.database.flow import Flow
from project.service.common.mqtt import MQTTService
from project.service.flow import FlowService
from project.core.exception import NoRecordError, BizError
from project.service.common.jpush import JpushService, FLOW_FLUSH


flow_router = APIRouter(prefix='/m', tags=['manager.flow'])


@flow_router.post('/flow/add', summary='新增流程')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_flow_add(request: Request,
                      name: str = Body('', max_length=30, title='服务流程名称'),
                      introduction: str = Body('', max_length=200, title='服务流程介绍'),
                      figure: str = Body('', max_length=200, title='数字人形象照'),
                      third_party_url: str = Body('', title='第三方链接'),
                      is_template: int = Body(0, title='是否为模板0(否)/1(是)'),
                      is_forbidden: int = Body(0, title='是否禁用'),
                      session=None,
                      body_params=None,
                      operator=None):
    """
    **desc**: 新增服务记录

    **url**: http(s)://{0}.udicaria.com/m/flow/add

    **method**: POST

    **params**:

        <body>:
            name: 服务流程名称
            introduction: 服务流程介绍
            figure: 数字人形象照
            third_party_url: 第三方链接
            is_template: 是否为模板 0(否)/1(是)
            is_forbidden: 是否禁用

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    flow = await FlowService.do_flow_add(session, operator, body_params)

    return json_response(data=flow.dict('id', 'code'))


@flow_router.post('/flow/update', summary='修改流程')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_flow_update(request: Request,
                         background_tasks: BackgroundTasks,
                         id: int = Body(0, title='服务流程id'),
                         code: str = Body('', title='服务流程编码'),
                         name: str = Body(DEFAULT_VALUE, max_length=30, title='服务流程名称'),
                         introduction: str = Body(DEFAULT_VALUE, max_length=200, title='服务流程介绍'),
                         hint: str = Body(DEFAULT_VALUE, max_length=135, title='底部提示'),
                         figure: str = Body(DEFAULT_VALUE, max_length=200, title='数字人形象照'),
                         matching_intent: str = Body(DEFAULT_VALUE, title='用户意愿'),
                         sop: list[SopItem] = Body(DEFAULT_VALUE, title='sop信息'),
                         inform_config: list[InformConfig] = Body(DEFAULT_VALUE, title='短信配置'),
                         third_party_url: str = Body(DEFAULT_VALUE, title='第三方链接'),
                         is_template: int = Body(DEFAULT_VALUE, title='是否为模板0(否)/1(是)'),
                         session=None,
                         body_params=None,
                         operator=None):
    """
    **desc**: 修改服务记录

    **url**: http(s)://{0}.udicaria.com/m/flow/update

    **method**: POST

    **params**:

        <body>:
            id: 服务流程id
            code: 服务流程编码
            name: 服务流程名称
            introduction: 服务流程介绍
            figure: 数字人形象照
            matching_intent: 用户意愿
            sop: [
                {
                    content: 内容
                    node_code: 节点编号
                }
            ]sop信息
            inform_config: [
                {
                    flow_role_id: 流程角色id
                    flow_process_id: 工单状态id
                }
            ] 短信配置
            third_party_url: 第三方链接
            is_template: 是否为模板 0(否)/1(是)

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    # 支持id 和 code 修改
    flow_id = body_params.pop('id', 0)
    flow_code = body_params.pop('code', '')
    if flow_id:
        flow = await Flow.fetch_one(session, wheres=(Flow.id == flow_id))
    elif flow_code:
        flow = await Flow.fetch_one(session, wheres=(Flow.code == flow_code))
    else:
        raise BizError('缺少流程id或编码')
    if not flow:
        raise BizError('服务流程不存在')
    # 校验重名
    if hasattr(body_params, 'name'):
        wheres = list()
        wheres.append(Flow.name == body_params.name)
        wheres.append(~Flow.is_deleted)
        wheres.append(Flow.is_template == flow.is_template)
        if not flow.is_template:
            wheres.append(Flow.organization_code == operator.organization_code)  # 不同机构下名称可以重复
        _flow = await Flow.fetch_one(session, wheres=wheres)
        if _flow and _flow.id != flow.id:
            raise BizError('名称重复')

    flow.set_model_value(**body_params.dict())

    await session.commit()

    # 极光推送
    background_tasks.add_task(JpushService.push, session, organization_code=operator.organization_code, flow_code=flow.code, node_code='', _type=FLOW_FLUSH)
    # MQTT 推送
    background_tasks.add_task(MQTTService.push, topic=f'cariabot/{operator.organization_code}', message=json.dumps({'action': 'flow_flush','flow_code': flow.code}, ensure_ascii=False).encode('utf-8'))

    return json_response()


@flow_router.get('/flow/list', summary='流程列表')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def get_flow_list(request: Request, session=None, operator=None):
    """
    **desc**: 服务流程列表

    **url**: http(s)://{0}.udicaria.com/m/flow/list

    **method**: POST

    **params**:

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    data = await Flow.fetch_all(session,
                                wheres=(Flow.organization_code == operator.organization_code, ~Flow.is_deleted),
                                orders=(Flow.id.desc()))

    items = [v.dict() for v in data]

    return json_response(data=items)


@flow_router.get('/flow/list_page', summary='流程列表(分页)')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def get_flow_list_page(request: Request,
                             name: str = Query('', title='编号/名称', description='编号/名称(模糊查询)'),
                             template_status: int = Query(-1, title='模板状态', description='-1(全部)/0(启用)/1(禁用)'),
                             is_template: int = Query(0, title='是否模板 0: 否, 1: 是', description='默认0'),
                             page: int = Query(1, title='第几页', description='默认1'),
                             page_size: int = Query(20, title='条数', description='每页显示的条数'),
                             session=None, operator=None):
    """
    **desc**: 服务流程列表(分页)

    **url**: http(s)://{0}.udicaria.com/m/flow/list_page

    **method**: GET

    **params**:

        <query>:
            name: 编号/名称(模糊查询)
            template_status: 模板状态 -1(全部)/0(启用)/1(禁用)
            is_template: 是否模板 0: 否, 1: 是
            page: 第几页
            page_size: 条数

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:{
                num: 总条数
                items: [
                    {
                        code: 编号
                        name: 名称
                        introduction: 介绍
                        is_forbidden: 是否被禁用
                        third_party_url: 第三方链接
                        figure: AI形象照(oss)
                        is_template: 是否模版
                    }
                ]
            }
            exec_time: 接口后端处理时长
        }
    """
    wheres = list()
    if name:
        wheres.append(or_(Flow.code.like(f'%{name}%'), Flow.name.like(f'%{name}%')))
    if template_status != -1:
        wheres.append(Flow.is_forbidden == template_status)
    wheres.append(Flow.is_template == is_template)
    if is_template == 0:
        wheres.append(Flow.organization_code == operator.organization_code)
    wheres.append(~Flow.is_deleted)

    # num
    record = await Flow.fetch_one(session, selects=(func.count(Flow.id)), wheres=wheres)
    num = if_none(record[0], 0)

    data = await Flow.fetch_all(session,
                                wheres=wheres,
                                offset=(page - 1) * page_size,
                                limit=page_size,
                                orders=(Flow.id.desc()))

    items = [v.dict() for v in data]
    ret_data = {
        'num': num,
        'items': items
    }

    return json_response(data=ret_data)


@flow_router.post('/flow/forbidden', summary='禁用模板')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_flow_forbidden(request: Request, code: str = Body(..., description='编号', embed=True), session=None):
    """
    **desc**: 禁用模板

    **url**: http(s)://{0}.udicaria.com/m/flow/forbidden

    **method**: POST

    **params**:

        <body>:
            code: 编号

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    await Flow.create_modify(session, wheres=(Flow.code == code), is_forbidden=1)

    return json_response()


@flow_router.post('/flow/unforbidden', summary='启用模板')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_flow_unforbidden(request: Request, code: str = Body(..., description='编号', embed=True), session=None):
    """
    **desc**: 启用模板

    **url**: http(s)://{0}.udicaria.com/m/flow/unforbidden

    **method**: POST

    **params**:

        <body>:
            code: 编号

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    await Flow.create_modify(session, wheres=(Flow.code == code), is_forbidden=0)

    return json_response()


@flow_router.post('/flow/template/make', summary='使用流程引入模板')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_template_add_from_flow(request: Request,
                                    flow_template_id: int = Body(0, title='服务流程模版id'),
                                    name: str = Body('', max_length=30, title='服务流程名称'),
                                    session=None,
                                    body_params=None,
                                    operator=None):
    """
    **desc**: 使用流程制作模版

    **url**: http(s)://{0}.udicaria.com/m/flow/template/make

    **method**: POST

    **params**:

        <body>:
            flow_template_id: 服务流程模版id
            name: 服务流程名称
            introduction: 服务流程介绍
            figure: 数字人形象照
            third_party_url: 第三方链接
            is_template: 是否为模板 0(否)/1(是)

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    flow = await FlowService.do_flow_add(session, operator, flow_template_id, body_params)

    return json_response(data=flow.dict('id', 'code'))


@flow_router.get('/flow/detail', summary='流程详情')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def get_flow_detail(request: Request, id: int = Query(0, title='服务流程id'), code: str = Query('', title='服务流程编码'), session=None):
    """
    **desc**: 服务流程详情

    **url**: http(s)://{0}.udicaria.com/m/flow/detail

    **method**: GET

    **params**:

        <query>:
            id: 服务流程id
            code: 服务流程编码

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: {
                code: 服务流程名称
                name: 服务流程编号
                introduction: 流程介绍
                matching_intent: 用户意愿
                sop: [
                    {
                        content: 内容
                        node_code: 节点编号
                    }
                ] sop信息
            }
            exec_time: 接口后端处理时长
        }
    """
    # 支持id 和 code 查询
    if id:
        flow = await Flow.fetch_one(session, wheres=(Flow.id == id))
    elif code:
        flow = await Flow.fetch_one(session, wheres=(Flow.code == code))
    else:
        raise BizError('缺少流程id或编码')
    if not flow:
        raise BizError('服务流程不存在')

    return json_response(data=flow.dict() if flow else {})


@flow_router.post('/flow/delete', summary='流程删除')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_flow_delete(request: Request, background_tasks: BackgroundTasks,
                         id: int = Body(0, title='流程id'),
                         code: str = Body('', title='编号'), session=None, operator=None):
    """
    **desc**: 删除服务流程

    **url**: http(s)://{0}.udicaria.com/m/flow/delete

    **method**: POST

    **params**:

        <body>:
            id: 服务流程id
            code: 服务流程编码

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    # 支持id 和 code
    if id:
        flow = await Flow.fetch_one(session, wheres=(Flow.id == id))
    elif code:
        flow = await Flow.fetch_one(session, wheres=(Flow.code == code))
    else:
        raise BizError('缺少流程id或编码')
    if not flow:
        raise BizError('服务流程不存在')
    flow.is_deleted = 1
    await session.commit()

    # 极光推送
    background_tasks.add_task(JpushService.push, session, organization_code=operator.organization_code, flow_code=flow.code, node_code='', _type=FLOW_FLUSH)
    # MQTT 推送
    background_tasks.add_task(MQTTService.push, topic=f'cariabot/{operator.organization_code}', message=json.dumps({'action': 'flow_flush','flow_code': flow.code}, ensure_ascii=False).encode('utf-8'))

    return json_response()


@flow_router.get('/combobox/flow/list', summary='流程列表(下拉框)')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def get_combobox_flow_list(request: Request, session=None, operator=None):
    """
    **desc**: 服务流程列表

    **url**: http(s)://{0}.udicaria.com/m/combobox/flow/list

    **method**: GET

    **params**:

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    data = await Flow.fetch_all(session,
                                wheres=(Flow.organization_code == operator.organization_code, ~Flow.is_deleted),
                                orders=(Flow.id.desc()))

    items = [v.dict('id', 'code', 'name') for v in data]

    return json_response(data=items)


@flow_router.post('/flow/agent/interaction', summary='agent交互')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_agent_interaction(request: Request,
                               id: int = Body(..., title='服务流程id'),
                               user_message: str = Body(..., title='用户话术'),
                               is_init: bool = Body(True, title='是否初始化'),
                               session=None,
                               operator=None):
    """
    **desc**: 服务流程agent交互

    **url**: http(s)://{0}.udicaria.com/m/flow/agent/interaction

    **method**: POST

    **params**:

        <body>:
            id: 服务流程id
            user_message: 用户话术
            is_init: 是否初始化记忆

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    result = await FlowService.do_flow_interaction(session, flow_id=id, user_message=user_message, operator=operator, is_init=is_init)

    return json_response(data=result)


@flow_router.post('/flow/template/add', summary='引入模版')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def do_flow_template_add(request: Request,
                               code: str = Body(..., title='服务流程编号'),
                               name: str = Body(..., max_length=30, title='服务流程名称'),
                               session=None,
                               operator=None):
    """
    **desc**: 引入模版

    **url**: http(s)://{0}.udicaria.com/m/flow/template/add

    **method**: POST

    **params**:

        <body>:
            code: 服务流程编号
            name: 服务流程名称

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    flow = await FlowService.do_copy_flow(session, operator, code, name, mode='make_template')

    return json_response(data=flow.dict('id', 'code'))


@flow_router.post('/flow/template/use', summary='使用模版')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def use_template(request: Request, code: str = Body(..., title='模板编号', embed=True), session=None, operator=None):
    """
    **desc**: 引入模版

    **url**: http(s)://{0}.udicaria.com/m/flow/template/use

    **method**: POST

    **params**:

        <body>:
            code: 服务流程编号
            name: 服务流程名称

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    flow = await FlowService.do_copy_flow(session, operator, code, '', mode='use_template')

    return json_response(data=flow.dict('id', 'code'))


@flow_router.get('/flow/template/list', summary='模版列表')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), verify_login=True)
@exec_duration(add_return=True)
async def get_template_list(request: Request, session=None):
    """
    **desc**: 模板列表

    **url**: http(s)://{0}.udicaria.com/m/flow/template/list

    **method**: POST

    **params**:

        <body>:
            code: 服务流程编号
            name: 服务流程名称

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    flows = await Flow.fetch_all(session, wheres=(~Flow.is_deleted, Flow.is_template, ~Flow.is_forbidden), orders=(Flow.id.desc()))

    return json_response(data=[v.dict() for v in flows])


